import { Context } from 'koa';
import jwt from 'jsonwebtoken';
import { ResponseUtil } from '../utils/response';

// 扩展Koa Context接口以包含用户信息
declare module 'koa' {
  interface Context {
    user?: {
      id: number;
      openid: string;
      isAdmin?: boolean;
    };
    id?: string;
  }
}

/**
 * JWT认证中间件
 */
export const authenticateToken = async (ctx: Context, next: () => Promise<void>) => {
  const authHeader = ctx.headers.authorization;
  const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

  if (!token) {
    ctx.status = 401;
    ctx.body = ResponseUtil.error(ctx, '访问令牌缺失', 'UNAUTHORIZED', 401);
    return;
  }

  try {
    const user = jwt.verify(token, process.env.JWT_SECRET as string) as any;
    ctx.user = user;
    await next();
  } catch (err) {
    ctx.status = 403;
    ctx.body = ResponseUtil.error(ctx, '访问令牌无效', 'FORBIDDEN', 403);
  }
};

/**
 * 管理员权限验证中间件
 */
export const requireAdmin = async (ctx: Context, next: () => Promise<void>) => {
  if (!ctx.user) {
    ctx.status = 401;
    ctx.body = ResponseUtil.error(ctx, '用户未认证', 'UNAUTHORIZED', 401);
    return;
  }

  if (!ctx.user.isAdmin) {
    ctx.status = 403;
    ctx.body = ResponseUtil.error(ctx, '需要管理员权限', 'FORBIDDEN', 403);
    return;
  }

  await next();
};

/**
 * 可选认证中间件（不强制要求认证）
 */
export const optionalAuth = async (ctx: Context, next: () => Promise<void>) => {
  const authHeader = ctx.headers.authorization;
  const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

  if (!token) {
    // 没有令牌，继续执行但不设置用户信息
    return await next();
  }

  try {
    const user = jwt.verify(token, process.env.JWT_SECRET as string) as any;
    ctx.user = user;
  } catch (err) {
    // 令牌无效，继续执行但不设置用户信息
  }

  await next();
};

/**
 * 检查用户是否为资源所有者或管理员
 */
export const requireOwnershipOrAdmin = (resourceUserId: number) => {
  return async (ctx: Context, next: () => Promise<void>) => {
    if (!ctx.user) {
      ctx.status = 401;
      ctx.body = ResponseUtil.error(ctx, '用户未认证', 'UNAUTHORIZED', 401);
      return;
    }

    // 如果是资源所有者或管理员，允许访问
    if (ctx.user.id === resourceUserId || ctx.user.isAdmin) {
      return await next();
    }

    ctx.status = 403;
    ctx.body = ResponseUtil.error(ctx, '无权限访问此资源', 'FORBIDDEN', 403);
  };
};

/**
 * 检查用户是否为资源所有者
 */
export const requireOwnership = (resourceUserId: number) => {
  return async (ctx: Context, next: () => Promise<void>) => {
    if (!ctx.user) {
      ctx.status = 401;
      ctx.body = ResponseUtil.error(ctx, '用户未认证', 'UNAUTHORIZED', 401);
      return;
    }

    // 如果是资源所有者，允许访问
    if (ctx.user.id === resourceUserId) {
      return await next();
    }

    ctx.status = 403;
    ctx.body = ResponseUtil.error(ctx, '无权限访问此资源', 'FORBIDDEN', 403);
  };
};

/**
 * 速率限制中间件（简单实现）
 */
export const rateLimit = (maxRequests: number, windowMs: number) => {
  const requests = new Map<string, { count: number; resetTime: number }>();

  return async (ctx: Context, next: () => Promise<void>) => {
    const key = ctx.ip || 'unknown';
    const now = Date.now();

    // 清理过期的记录
    for (const [ip, data] of requests.entries()) {
      if (now > data.resetTime) {
        requests.delete(ip);
      }
    }

    // 检查当前IP的请求次数
    if (!requests.has(key)) {
      requests.set(key, { count: 1, resetTime: now + windowMs });
      return await next();
    }

    const requestData = requests.get(key)!;

    if (requestData.count >= maxRequests) {
      const resetTime = Math.ceil((requestData.resetTime - now) / 1000);
      ctx.set('Retry-After', resetTime.toString());
      ctx.status = 429;
      ctx.body = ResponseUtil.error(ctx, `请求过于频繁,请在${resetTime}秒后重试`, 'RATE_LIMIT_EXCEEDED', 429);
      return;
    }

    requestData.count++;
    await next();
  };
};

/**
 * API密钥认证中间件（用于AI服务等外部API）
 */
export const authenticateApiKey = async (ctx: Context, next: () => Promise<void>) => {
  const apiKey = ctx.headers['x-api-key'] as string;

  if (!apiKey) {
    ctx.status = 401;
    ctx.body = ResponseUtil.error(ctx, 'API密钥缺失', 'UNAUTHORIZED', 401);
    return;
  }

  // 这里应该从数据库或配置中验证API密钥
  const validApiKeys = process.env.VALID_API_KEYS?.split(',') || [];

  if (!validApiKeys.includes(apiKey)) {
    ctx.status = 403;
    ctx.body = ResponseUtil.error(ctx, 'API密钥无效', 'FORBIDDEN', 403);
    return;
  }

  await next();
};


/**
 * 请求ID中间件
 */
export const requestId = async (ctx: Context, next: () => Promise<void>) => {
  ctx.id = ctx.headers['x-request-id'] as string || generateRequestId();
  ctx.set('X-Request-ID', ctx.id);
  await next();
};

/**
 * 生成请求ID
 */
function generateRequestId(): string {
  return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}

/**
 * Koa2 异步错误处理包装器
 */
export const asyncHandler = (fn: Function) => {
  return async (ctx: Context, next: () => Promise<void>) => {
    try {
      await fn(ctx, next);
    } catch (err) {
      ctx.app.emit('error', err, ctx);
    }
  };
};